Zustand 状态管理
在大型 React 项目中,使用 Zustand 管理全局状态是一种轻量、灵活且性能优秀的方案。以下是以一个 Todo List(待办事项)系统 为例,详细说明如何在大型项目中使用 Zustand 管理全局状态及操作方法。
🧩 一、状态设计
以 Todo List 为例,全局状态包括:
- 所有待办项
todos - 当前筛选条件
filter(如 all / completed / active) - 异步加载状态
loading - 错误信息
error(用于接口错误提示)
📦 二、安装 Zustand
bash
pnpm add zustand🏗️ 三、构建 Store(store/todoStore.ts)
ts
import { create } from 'zustand';
export type Todo = {
id: string;
title: string;
completed: boolean;
};
type Filter = 'all' | 'completed' | 'active';
interface TodoStore {
todos: Todo[];
filter: Filter;
loading: boolean;
error: string | null;
// actions
fetchTodos: () => Promise<void>;
addTodo: (title: string) => void;
toggleTodo: (id: string) => void;
removeTodo: (id: string) => void;
setFilter: (filter: Filter) => void;
}
export const useTodoStore = create<TodoStore>((set, get) => ({
todos: [],
filter: 'all',
loading: false,
error: null,
fetchTodos: async () => {
set({ loading: true, error: null });
try {
// 假设接口请求
const response = await fetch('/api/todos');
const data: Todo[] = await response.json();
set({ todos: data });
} catch (err: any) {
set({ error: err.message || 'Failed to fetch todos' });
} finally {
set({ loading: false });
}
},
addTodo: (title) => {
const newTodo: Todo = {
id: crypto.randomUUID(),
title,
completed: false
};
set({ todos: [...get().todos, newTodo] });
},
toggleTodo: (id) => {
set({
todos: get().todos.map((todo) => (todo.id === id ? { ...todo, completed: !todo.completed } : todo))
});
},
removeTodo: (id) => {
set({ todos: get().todos.filter((todo) => todo.id !== id) });
},
setFilter: (filter) => set({ filter })
}));🧪 四、使用状态和操作
tsx
import { useTodoStore } from '@/store/todoStore';
function TodoList() {
const { todos, filter, toggleTodo, removeTodo } = useTodoStore();
const filteredTodos = todos.filter((todo) => {
if (filter === 'completed') return todo.completed;
if (filter === 'active') return !todo.completed;
return true;
});
return (
<ul>
{filteredTodos.map((todo) => (
<li key={todo.id}>
<input type="checkbox" checked={todo.completed} onChange={() => toggleTodo(todo.id)} />
{todo.title}
<button onClick={() => removeTodo(todo.id)}>删除</button>
</li>
))}
</ul>
);
}⚙️ 五、Filter 设置与新增 Todo
tsx
function TodoControls() {
const { filter, setFilter, addTodo } = useTodoStore();
const [input, setInput] = useState('');
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button
onClick={() => {
addTodo(input);
setInput('');
}}
>
添加
</button>
<select value={filter} onChange={(e) => setFilter(e.target.value as any)}>
<option value="all">全部</option>
<option value="active">未完成</option>
<option value="completed">已完成</option>
</select>
</div>
);
}🔍 六、项目结构建议(中大型项目)
src/
├── store/
│ └── todoStore.ts # Zustand store
├── components/
│ ├── TodoList.tsx
│ └── TodoControls.tsx
├── pages/
│ └── Home.tsx✅ 七、进阶建议
Middleware 使用
- 如 Zustand 的
persist用于本地持久化,devtools配合 Redux DevTools 调试。
- 如 Zustand 的
Selectors 优化
减少组件不必要的重新渲染,例如:
tsconst todos = useTodoStore((state) => state.todos);
组合多个 Store
- 拆分不同模块(如 AuthStore、TodoStore),每个模块一个 store 文件。
异步操作封装
- 可将异步 API 封装到
services/中,在 store 内调用,保持 store 的纯粹性。
- 可将异步 API 封装到
🧠 总结
使用 Zustand 管理 Todo List 全局状态的优势:
| 优点 | 表现 |
|---|---|
| 简洁轻量 | 无需引入 reducer / action 概念 |
| 无 Provider | 组件中直接使用,无需 Context 包裹 |
| 高性能 | 支持选择性订阅,避免不必要更新 |
| 可拓展 | 支持中间件、组合多个 store |